﻿#include "shellutils.h"

#include "appcommon.h"
#include <QDebug>
#include <QElapsedTimer>
#include <QFile>
#include <QProcess>
#include <QRegularExpression>
#include <QThread>

#include "config/appconfig.h"
#include "util/util.h"
ShellUtils::ShellResult ShellUtils::runShell(const QString &shellFilePath, const QStringList &args,
                                             const QString &grepPattern, int timeout) {
    QFile file(shellFilePath);
    if (!file.exists()) {
        return ShellUtils::ShellResult::errorResult(
            QString(tr("Shell[%1]不存在")).arg(shellFilePath), 0);
    }

    QStringList shell_args;
    shell_args << shellFilePath;
    shell_args << args;
    return runCommand("/bin/bash", shell_args, grepPattern, timeout);
}

ShellUtils::ShellResult ShellUtils::runCommand(const QString &command, const QStringList &args,
                                               const QString &grepPattern, int timeout) {
    if (timeout <= 0) {
        AppConfig &config = AppConfig::instance();
        timeout =  60 * 1000;
    }
    timeout = qMax(timeout, 120000);

    QElapsedTimer elapsedTimer;
    elapsedTimer.start();
    if (command.isEmpty()) {
        return ShellUtils::ShellResult::errorResult(tr("命令为空"), 0);
    }

    QProcess process;
    process.start(command, args);
    if (!process.waitForStarted(timeout)) {
        process.kill();
        process.waitForFinished();
        return ShellUtils::ShellResult::errorResult(tr("无法启动进程：") + command,
                                                    elapsedTimer.elapsed());
    }

    if (!process.waitForFinished(timeout)) {
        process.kill();
        process.waitForFinished();
        return ShellUtils::ShellResult::errorResult(tr("进程超时：") + command, elapsedTimer.elapsed());
    }

    ShellUtils::ShellResult result;
#ifdef CPPC_OS_WINDOWS
    QByteArray outputData = process.readAllStandardOutput();
    result.result = QString::fromLocal8Bit(outputData);
#else
    result.result = process.readAllStandardOutput();
#endif
    if (result.result.isEmpty()) {
        result.msg = tr("命令无返回数据");
    } else {
        if (!grepPattern.isEmpty()) {
            QStringList lines = result.result.split("\n");
            QStringList resultStr;
            foreach (const QString &line, lines) {
                if (!grepPattern.isEmpty() && !line.contains(grepPattern)) {
                    continue;
                }
                resultStr.append(line);
            }
            if (resultStr.size() <= 0) {
                result.result = "";
                result.msg = tr("过滤后数据为空");
            } else {
                result.result = resultStr.join("\n");
            }
        }
    }
    result.elapsedTime = elapsedTimer.elapsed();
    int exitCode = process.exitCode();
    result.exitCode = exitCode;
    result.cmdResult = result.result;

    if (exitCode == 0) {
        result.success = true;
    } else {
        result.success = false;
        result.result = tr("命令执行失败：") + command + " " + args.join(" ");
    }
    process.kill();
    process.waitForFinished();
    process.deleteLater();
    return result;
}

ShellUtils::ShellResult ShellUtils::runCommand(const QStringList &command,
                                               const QString &grepPattern, int timeout) {
    if (command.size() <= 0) {
        return ShellUtils::ShellResult::errorResult(tr("命令为空"), 0);
    }
    return runCommand(command.at(0), command.mid(1, command.size() - 1), grepPattern, timeout);
}

QString ShellUtils::generateMatchString(QString keyword, QString matchType) {
    if (keyword.isEmpty()) {
        return "";
    }
    matchType = matchType.trimmed();
    if (matchType == "start") {
        return "^" + QRegularExpression::escape(keyword) + ".*";
    } else if (matchType == "end") {
        return ".*" + QRegularExpression::escape(keyword) + "$";
    } else if (matchType == "contain") {
        return ".*" + QRegularExpression::escape(keyword) + ".*";
    }
    return QRegularExpression::escape(keyword);
}

ShellUtils::ShellResult ShellUtils::ping(QString ip, int timeout, int times) {
    if (AppCommon::isNullOrEmpty(ip)) {
        return ShellUtils::ShellResult::errorResult(tr("包名为空"), 0);
    }
    QStringList commands;
    commands << "ping";
    commands << ip;
    commands << "-W";
    commands << QString::number(timeout);
    commands << "-c";
    commands << QString::number(times);
    return runCommand(commands);
}
